#pragma once

#include <vector>
#include "Mutex.hpp"
#include "Sem.hpp"

using namespace MutexModule;
using namespace SemModule;

const int default_cap = 5;

template<typename T>
class RingQueue
{
public:
    RingQueue(int cap = default_cap)
        :_rq(cap)
        ,_cap(cap)
        ,_blank_sem(cap)
        ,_p_step(0)
        ,_data_sem(0)
        ,_c_step(0)
    {
    }
    void Push(const T& in)
    {
        _blank_sem.P();
        LockGuard lockguard(_p_mutex);
        _rq[_p_step] = in;
        ++_p_step;
        _p_step %= _cap;
        _data_sem.V();
    }
    T& Pop()
    {
        _data_sem.P();
        LockGuard lockguard(_c_mutex);
        T& data = _rq[_c_step];
        ++_c_step;
        _c_step %= _cap;
        _blank_sem.V();

        return data;
    }
private:
    std::vector<T> _rq;
    int _cap;

    // 生产者
    Sem _blank_sem; // 空位数
    int _p_step;
    Mutex _p_mutex; // 生产者之间的互斥

    // 消费者
    Sem _data_sem; // 资源数
    int _c_step;
    Mutex _c_mutex; // 消费者之间的互斥
};